<?php

/**
 * alltosun.com 访问权限控制 Acl.php
 * ============================================================================
 * 版权所有 (C) 2007-2011 北京互动阳光科技有限公司，并保留所有权利。
 * 网站地址: http://www.alltosun.com
 * ----------------------------------------------------------------------------
 * 许可声明：这是一个开源程序，未经许可不得将本软件的整体或任何部分用于商业用途及再发布。
 * ============================================================================
 * $Author: 高竞竞 (gaojj@alltosun.com) $
 * $Date: 2011-7-25 下午12:33:32 $
 * $Id: Acl.php 22519 2013-04-08 07:50:40Z weisd $
*/

class AnAcl
{
    public static $debug = false;

    /**
     * 当前登录用户是否拥有指定资源的指定操作的权限
     * @param string $res_name
     * @param string $action_name
     * @param int $res_id
     * @return bool
     */
    public static function isAllow($res_name, $action_name = '', $res_id = 0)
    {
        $debug = self::$debug;

        // 超级管理员
        if (user_helper::is_admin()) {
            return true;
        }

        // 未注册权限项的资源，除管理员外均无权限
        $auth_res_info = _uri('auth_res', array('res_name'=>$res_name));
        if (!$auth_res_info) {
            if ($debug) self::log('No auth_res found of '.$res_name);
            return false;
        }

        $user_id = user_helper::get_user_id();
        // 未登录用户，没有权限
        // @FIXME 目前ACL只运用在后台，该限制与前台游客可浏览的权限有冲突
        if (!$user_id) {
            return false;
        }

        // 未注册自定义权限动作的资源，查看该用户有无该资源的所有管理权限
        $basic_action = user_config::$auth_basic_action;
        $parent_action = '';
        if (!isset($basic_action[$action_name])) {
            $filter = array(
                'auth_res_id' => $auth_res_info['id'],
                'action_name' => $action_name
            );
            $auth_action_info = _uri('auth_action', $filter);
            if (!$auth_action_info) {
                // 查看该用户有无该资源的所有管理权限
                $result = self::isUserAccessRes($user_id, '*', '*', $res_name, $res_id);
                if ($result) {
                    if ($debug) self::log('Own all privilege of '.$res_name.'-'.$res_id);
                    return $result;
                }
                if ($debug) self::log('No auth_action found of '.$res_name.'-'.$res_id.' with action_name:'.$action_name);
                return false;
            }
            $parent_action = $auth_action_info['parent_action'];
        }

        // 用户 VS 资源
        $result = self::isUserAccessRes($user_id, $action_name, $parent_action, $res_name, $res_id);
        if ($result !== null) {
            return $result;
        }

        // 都没有设定的话，默认无权限
        return false;
    }

    /**
     * 指定用户是否有访问指定资源指定操作的权限
     * @param int $user_id
     * @param string $action_name
     * @param string $parent_action
     * @param string $res_name
     * @param int $res_id
     * @return bool|null null为没有定义权限
     */
    private static function isUserAccessRes($user_id, $action_name, $parent_action, $res_name, $res_id = 0)
    {
        // 当前用户是否有该资源的权限
        $result = self::isAccessRes($user_id, 'user', $action_name, $parent_action, $res_name, $res_id);
        if ($result !== null) {
            return $result;
        }

        // 当前用户所属用户组是否有该资源的权限
        $user_role_ids = user_helper::get_user_role_ids($user_id);

        $result = self::isAccessRes($user_role_ids, 'role', $action_name, $parent_action, $res_name, $res_id);
        if ($result !== null) {
            return $result;
        }

        return null;
    }

    /**
     * 指定用户|用户组是否有访问指定资源指定操作的权限
     * @param int|array $role_id
     * @param string $role_type 值为role，代表用户组；user代表用户
     * @param string $action_name
     * @param string $parent_action
     * @param string $res_name
     * @param int $res_id
     * @return bool|null null为没有定义权限
     */
    private static function isAccessRes($role_id, $role_type, $action_name, $parent_action, $res_name, $res_id = 0)
    {
        if (is_array($role_id)) {
            $params = func_get_args();
            foreach ($role_id as $v) {
                $params[0] = $v;
                $result = call_user_func_array(array(__CLASS__, __METHOD__), $params);
                if ($result !== null) {
                    return $result;
                }
            }
            return null;
        }

        $filter = array(
            'res_name' => $res_name
        );

        if ($role_type == 'role') {
            $filter['role_id'] = $role_id;
        } else {
            $filter['user_id'] = $role_id;
        }

        if (!$res_id) {
            // 对资源类型是否有定义权限
            return self::checkDefinedAuth($filter, $action_name, $parent_action);
        }

        // 单个资源是否有定义权限
        $filter['res_id'] = $res_id;
        $result = self::checkDefinedAuth($filter, $action_name, $parent_action);
        if ($result !== null) {
            return $result;
        }

        // 如果当前资源没有单独定义权限，则看资源所属分类是否有定义权限
        // @todo 目前以一个资源只属于一个分类，需要增加一个资源属于多个不同类型的分类的处理
        $res_info = _uri($res_name, $res_id);
        if (!empty($res_info['category_id'])) {
            $filter['category_id'] = $res_info['category_id'];
            if (!empty($res_info['category_type'])) {
                $filter['category_type'] = $res_info['category_type'];
            }
            $result = self::checkDefinedAuth($filter, $action_name, $parent_action);
            if ($result !== null) {
                return $result;
            }
        }

        // 资源所属类型是否有定义权限
        return self::isAccessRes($role_id, $role_type, $action_name, $parent_action, $res_name);
    }

    /**
     * 验证角色有无定义符合指定条件的资源进行某个操作的权限
     * @param array $filter 用来定位资源的过滤器，如果含role_id则角色为用户组；含user_id则为用户（默认）
     * @param string $action_name 操作代码
     * @return bool|null null为没有定义权限
     */
    private static function checkDefinedAuth($filter, $action_name, $parent_action)
    {
        $debug = self::$debug;
        if ($debug) debug_print_backtrace();

        $role_table = isset($filter['role_id']) ? 'auth_role' : 'auth_user';
        $auth_list = _model($role_table)->getList($filter);
        if (!$auth_list) {
            return null;
        }

        $action_name_permission = array();
        foreach ($auth_list as $v) {
            $action_name_permission[$v['action_name']] = $v['permission'];
        }

        // 如果当前操作有单独定义权限
        if (isset($action_name_permission[$action_name])) {
            if ($debug) self::log('Action:'.$action_name.' has a definition.');
            return $action_name_permission[$action_name] == 'allow';
        }
        // 如果当前操作无权限，且非基本操作，则查看上级操作是否有定义权限
        if ($parent_action && isset($action_name_permission[$parent_action])) {
            if ($debug) self::log('Parent action:'.$parent_action.' has a definition.');
            return $action_name_permission[$parent_action] == 'allow';
        }
    }

    /**
     * 用户有无定义过权限
     * @param int $user_id
     * @return bool
     */
    public static function hasDefinedAuth($user_id = 0)
    {
        if (!$user_id) {
            $user_id = user_helper::get_user_id();
        }

        if (!$user_id) {
            return false;
        }

        if (user_helper::is_admin($user_id)) {
            return true;
        }

        $user_role_ids = user_helper::get_user_role_ids($user_id);
        foreach ($user_role_ids as $role_id) {
            if (_model('auth_role')->read(array('role_id'=>$role_id))) {
                return true;
            }
        }

        return !!_model('auth_user')->read(array('user_id'=>$user_id));
    }

    private static function log($message)
    {
        echo $message.'<br />';
    }
}
?>